#ifndef _CPSYSTEM_H_
#define _CPSYSTEM_H_

#include "main.h"
#include "stairmath.h"

// I credit Chris Hecker to my usage of the idea that if
// a collision happens, you should re-test all the
// other vertices after you apply the collision. Also,
// you should give up after so many collisions in case
// we run into an infinite loop.
#define MAX_ALLOWABLE_COLLISIONS_PER_TRY		50

// C is for class and P is for physics. Maybe
// "physics system" isn't really the best name for this
// class, but when I think of 'system' I not only think
// of objects in themselves, but also of influences
// and laws that govern their transformations in space.

class CPSystem
{
public:
	typedef enum { eStair, eCube, eOther } eType;

protected:
	///////////////////////////////////
	// Solid information
	_VERTEX* m_vStatic;	// Vertices that define the
						// body always relative to
						// it's origin

	_VERTEX* m_v;		// Vertices in the world

	_FACE* m_f;			// Faces
	_TEXCOORD* m_tex;	// Texture coords


	int m_nVertices;	// Vertex count
	int m_nFaces;		// Face count

	unsigned int CollisionDetect(CPSystem* p1, CPSystem* p2);
	unsigned int Collide(CPSystem* pSysA, CPSystem* pSysB, _FACE* f, _VERTEX* pV);

	eType m_Type;

public:
	CPSystem();
	~CPSystem();

	eType GetType() { return m_Type; }

	// Called once per frame. This function is
	// used to make the object interact with the
	// universe
	virtual void Action(CPSystem* p);

	// Called once per frame. This function will
	// alter the body of this object based on
	// what happened in Action().
	virtual void Reaction(float t);

	// A::Influence(B) has the effect of object A
	// being influenced by object B. For example, object
	// A (a die) collides with and bounces away
	// from object B (a stair).
	virtual void Influence(CPSystem* p) {};

	virtual void Draw() {};
	virtual void DrawShadow(GLfloat shadowMat[4][4]) {};

	_FACE* GetFaces() { return m_f; }
	int GetFaceCount() { return m_nFaces; }

	_VERTEX* GetVertices() { return m_v; }
	int GetVertexCount() { return m_nVertices; }

	///////////////////////////////////
	// Physics state that we want to
	// retain for each frame
	_VERTEX m_vCenter;		// Center of gravity
	_VECTOR m_vVel;			// Velocity (m/s)
	_VECTOR m_vwp;			// Angular momentum
	float m_Mass;			// Mass (kg)
	float m_OneOverMass;	// 1 / Mass (kg^-1)
	_VECTOR m_vwVel;		// Angular velocity
	CMatrix3x3 m_matInvI;	// Inverse Inertia Tensor (The variable I^-1)
	CMatrix3x3 m_matO;		// Orientation matrix

	///////////////////////////////////
	// Physics states that we
	// calculate in each frame
	_VECTOR m_vF;		// Force
	_VECTOR m_vT;		// Torque
	CMatrix3x3 m_matInvWI;	// Inverse world inertia tensor	

	///////////////////////////////////
	// Demo specific variables (not
	// physics-related)
	float m_tLife;		// Amount of time this object has existed

	///////////////////////////////////
	// Next node in linked list
	CPSystem* m_pNext;
};

#endif